package com.leonzhangxf.aop.primary;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;

/**
 * The interceptor demo for AOP scenario.
 * <p>
 * 冗余添加 {@link Component}，声明其是一个bean。其实已经在 {@link Configuration} 中集成。
 * 这里分开认为注解是两个部分：
 * {@link Configuration}、{@link EnableAspectJAutoProxy} 负责启用AOP；
 * {@link Component}、{@link Aspect} 用于标记此实例为spring bean，并且是一个切面类
 * （当然，spring默认也会实例化标记了 {@link Aspect} 注解的类）。
 *
 * @author leonzhangxf
 * @see Configuration
 * @see EnableAspectJAutoProxy
 * @see Component
 * @see Aspect
 */
@Configuration
@EnableAspectJAutoProxy
@Component
@Aspect
public class HelloWorldInterceptor {

    /**
     * this 代表生成的代理对象
     *
     * 实现了对应接口或继承了指定类的代理对象
     */
    @Pointcut("this(com.leonzhangxf.aop.bean.HelloWorldService)")
    void thisPointcut() {

    }

    /**
     * target 代表被代理的实例
     *
     * 实现了对应接口或者继承了指定类的被代理对象
     */
    @Pointcut("target(com.leonzhangxf.aop.bean.HelloWorldService)")
    void targetPointcut() {

    }

    /**
     * 切点也可以根据声明，具备方法的包域。public private protected等
     */
    @Pointcut("bean(helloWorldService)")
    private void beanPointcut() {

    }

    @Pointcut("within(com.leonzhangxf.aop.bean..*)")
    void withinPointcut() {
    }

    @Pointcut("execution(* com.leonzhangxf.aop.bean.*.*(..))")
    void commonPointcut() {
    }

    @Pointcut("@annotation(com.leonzhangxf.aop.bean.HelloWorldAnno)")
    protected void commonPointcutWithAnnotation() {
    }

    @Pointcut("execution(* com.leonzhangxf.aop.bean.HelloWorldService.helloWorld())")
    public void helloWorldPointcut() {
    }

    @Pointcut("execution(* com.leonzhangxf.aop.bean.HelloWorldService.helloWorld(java.lang.String))")
    public void helloWorldWithMessagePointcut() {
    }

    @Before("commonPointcut()")
    public void commonAdviseBefore() {
        System.out.println("The interceptor worked. Intercept the method invoke below " +
            "the package com.leonzhangxf.bean.");
    }

    @AfterReturning(value = "commonPointcutWithAnnotation()", returning = "value")
    public void commonAdviseWithAnnotationAfterReturning(Object value) {
        System.out.println(value);
        System.out.println("The interceptor worked. Intercept the method invoke with annotation HelloWorldAnno.");
    }

    @AfterThrowing(value = "helloWorldWithMessagePointcut()", throwing = "ex")
    public void helloWorldWithMessageAdviseAfterThrowing(RuntimeException ex) {
        System.out.println(ex.getMessage());
        System.out.println("The interceptor worked. Intercept the hellWorld with message method.");
    }

    @After("helloWorldPointcut()")
    public void helloWorldAdviseAfter() {
        System.out.println("The interceptor worked. Intercept the hellWorld.");
    }

    @Around("helloWorldWithMessagePointcut()")
    public Object helloWorldWithMessageAdviseAround(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("The interceptor worked. Intercept the hellWorld with message method.");
        return joinPoint.proceed();
    }
}
